/**
 * 处理输入终端点击事件的函数。
 *
 * 该函数会创建一个隐藏的文件输入元素，监听其变化事件，
 *
 * 当用户选择文件后，调用文件处理函数，并清理临时创建的输入元素。
 */
function inputFileButtonClickEvent() {
	/** 创建一个文件输入元素 */
	const fileInput = document.createElement('input');
	// 设置输入元素的类型为文件选择
	fileInput.type = 'file';
	// 设置允许选择的文件扩展名，包含支持的扩展名和所有文本类型
	fileInput.accept = fileValidExtensions.join(',');
	// 将输入元素隐藏
	fileInput.style.display = 'none';
	// 监听文件输入元素的变化事件
	fileInput.addEventListener('change',
		event => {
			// 若用户选择了文件，则处理第一个文件
			if (event.target.files.length) handleFile(event.target.files[0]);
			// 清理临时创建的输入元素
			document.body.removeChild(fileInput);
		}
	);
	// 将文件输入元素添加到页面中
	document.body.appendChild(fileInput);
	// 触发文件选择对话框
	fileInput.click();
};

/**
 * 统一文件处理函数（用于点击和拖拽）
 *
 * @param {File} file - 要处理的文件对象
 */
function handleFile(file) {
	/** 获取文件的扩展名并转换为小写 */
	const extension = file.name.slice(file.name.lastIndexOf('.')).toLowerCase();
	// 检查是否为图片文件或视频文件
	if (visionExtensions.includes(extension) || file.type.startsWith('image/') || file.type.startsWith('video/')) {
		// 检查文件大小是否超过3MB
		if (file.size > 3 * 1024 * 1024) return showSystemMessage('图片太大了, 能给月华换一个吗?', 'error');
		// 处理图片文件或视频文件
		processImageFile(file);
	}
	// 检查是否为ZIP文件
	else if (extension === '.zip') processZipFile(file);
	// 优先使用扩展名检测，若扩展名在支持的列表中，则按文本格式读取文件
	else if (fileValidExtensions.includes(extension)) readFileAsText(file);
	// 备用MIME类型检测（仅作为后备方案），若文件类型为文本类型或在支持的MIME类型列表中，则按文本格式读取文件
	else if (file.type.startsWith('text/') || fileValidTypes.includes(file.type)) readFileAsText(file);
	// 最后尝试读取小文件（文件大小小于1MB），使用安全尝试方式读取未知类型文件
	else if (file.size < 1024 * 1024) attemptReadAsText(file);
	// 若以上条件都不满足，说明无法读取该文件，显示错误提示信息
	else showSystemMessage('月华无法阅读这个文件', 'error');
};

/**
 * 安全尝试读取未知类型文件
 *
 * 该函数会尝试以文本格式读取文件，读取完成后检测文件内容是否包含二进制数据，
 *
 * 若包含则显示错误信息，否则将文件内容传递给 函数处理。
 *
 * @param {File} file - 需要读取的文件对象
 */
function attemptReadAsText(file) {
	/** 创建一个 FileReader 实例，用于读取文件内容 */
	const reader = new FileReader();
	// 当文件读取成功完成时触发的回调函数
	reader.onload = event => {
		/** 获取文件读取结果 */
		const content = event.target.result;
		/** 检测文件内容是否包含非可打印字符（二进制数据） */
		const hasBinary = /[\x00-\x08\x0E-\x1F]/.test(content);
		// 根据检测结果处理文件：若包含二进制数据则显示错误信息，否则处理文件内容
		hasBinary ? showSystemMessage('文件包含二进制数据', 'error') : tryCaptureConfig(file.name, content);
	};
	// 当文件读取过程中发生错误时，显示文件读取失败的错误提示信息
	reader.onerror = error => showSystemMessage(`${error.name} | ${error.message} | ${error.stack}`, "error");
	// 以文本格式读取指定的文件
	reader.readAsText(file);
};

/**
 * 尝试根据文件类型和内容配置进行相应处理
 *
 * @param {string} fileName - 文件名
 *
 * @param {string} fileContent - 文件内容
 */
function tryCaptureConfig(fileName, fileContent) {
	try {
		// 检查文件是否为 JSON 文件
		if (fileName.toLowerCase().endsWith('.json')) {
			/** 解析 JSON 文件内容 */
			const config = JSON.parse(fileContent);
			/** 获取 JSON 数据的元版本 */
			const version = config?.meta?.version;
			// 检查 JSON 数据的元版本是否在支持的版本列表中
			if (chatHistoryMetaVersion.has(version)) loadChatHistory(config);
			// 若版本不匹配，则按文件分块导入处理
			else fileSliceImport(fileName, fileContent);
		}
		// 若不是 JSON 文件，同样按文件分块导入处理
		else fileSliceImport(fileName, fileContent);
	}
	catch (error) {
		// 捕获异常并显示错误信息
		showSystemMessage(`${error.name} | ${error.message} | ${error.stack}`, "error");
	}
};

/**
 * 将文件内容分块处理，并创建对应的消息对象。
 *
 * 对于大文件会进行特定处理，如导出聊天记录、清理历史记录、移除注释和格式化内容等。
 *
 * @param {string} fileName - 文件名
 *
 * @param {string} fileContent - 文件内容
 */
function fileSliceImport(fileName, fileContent) {
	/** 定义需要保留格式的文件扩展名列表 */
	const preserveFormatTypes = ['.py', '.txt', '.csv'];
	/** 判断文件是否为大文件, 即文件内容长度是否大于等于 用户消息截断长度 */
	const isLargeFile = fileContent.length >= messageSliceLength.value;
	// 若文件内容长度一定比例, 则显示系统消息, 提醒用户下次提供重点段落
	if (isLargeFile) showSystemMessage('这个文件有些长... 下次能给月华重点段落吗？', 'error');
	// 若文件是大文件，且文件扩展名不在需要保留格式的列表中
	if (isLargeFile && !preserveFormatTypes.some(ext => fileName.toLowerCase().endsWith(ext))) {
		// 移除文件内容中的代码注释
		fileContent = removeCodeComments(fileContent);
		// 将文件内容中的多个换行符替换为单个空格
		fileContent = fileContent.replace(/[\r\n]+/g, ' ');
		// 将文件内容中的多个连续空格或制表符替换为单个空格
		fileContent = fileContent.replace(/[ \t]{2,}/g, ' ');
	}
	/** 将文件内容按段落分割为多个字符串 */
	let pages = splitTextToStrings(fileContent);
	// 为每个文件块添加文件名和段落索引
	pages = pages.map((page, index) => `[ 文件: ${fileName} | 页码: ${index + 1}/${pages.length} ] |>\n ${page}`);
	// 为每个文件块创建对应的消息对象
	pages.forEach(page => createMessageObject("user", page, true, false, true));
	// 创建一条询问消息，询问用户希望如何处理该文件，并渲染到聊天历史记录面板中
	tracelessRenderMessage(`月华拿到📄< \`\`\` ${fileName} \`\`\` >啦～ 您希望了解那些内容呢？`, chatHistoryPanel);
	// 判断是否为开发者模式
	if (isDeveloperMode) {
		/** 序列化消息数组 */
		const messagesJson = JSON.stringify(pages, null, 2);
		/** 消息格式的修饰符 */
		const modify = ['<think>\n```json\n', '\n```\n</think>']
		/** 渲染处理后的消息数组 */
		const messageElement = tracelessRenderMessage(modify[0] + messagesJson + modify[1], chatHistoryPanel);
		// 为think区块添加折叠功能
		messageElement?.querySelectorAll(".toggle_think_button").forEach(bindFoldingButton);
	};
};